//
//  PSFilterWhisterAfterDeclarerMoveOpen.m
//  PrefCore
//
//  Created by Sergey on 6/20/14.
//  Copyright (c) 2014 Play-on-smart. All rights reserved.
//

#import "PSFilter.h"
#import "PSFilterUtil.h"

// The basic idea of this filter is to beat declarer card with lowest possible cards.
// In case there are no such cards in player's hand, use lowest candidates cards
// to reduce the size of the tree.
PSHandHash PSFilterWhisterAfterDeclarerMoveOpen(
    PSEvaluator* evaluator
,   PSHandHash candidates
,   PSHandHash* hands
,   PSPlayerId player
,   PSTrickHash trick
,   PSCardSuit trump
,   uint32_t round
,   uint8_t handIndex
,   PSPlayerId declarer
) {
    PSCardRank best = 2*kRankAce;
    PSHandHash lc = PSFilterGetLowestCandidates(candidates);
    PSHandHash filtered = 0;
    if (handIndex == 1) {
        PSPlayerId next = PSGameNextPlayerId(player);
        uint8_t hand2Index = handIndex + 1;
        PSHandHash candidates2 = [evaluator
            moveCandidatesWithHands:hands
            player:next
            trick:trick
            trump:trump
            round:round
            handIndex:hand2Index
            declarer:declarer
        ];
        for (PSCardHash h1 = [evaluator startWithCandidates:candidates]
        ;   h1 != 0
        ;   h1 = [evaluator nextWithCandidates:candidates andCurrent:h1]) {
            PSCard *c1 = [PSCard cardWithHash:h1];
            trick = PSTrickAddCardPlayer(trick, player, c1.compressed);
            for (PSCardHash h2 = [evaluator startWithCandidates:candidates2]
            ;   h2 != 0
            ;   h2 = [evaluator nextWithCandidates:candidates2 andCurrent:h2]) {
                PSCard *c2 = [PSCard cardWithHash:h2];
                PSCardRank sum = c1.rank + c2.rank;
                trick = PSTrickAddCardPlayer(trick, next, c2.compressed);
                int winner = PSTrickWinner(trick, trump);
                if (winner != declarer && sum <= best) {
                    filtered = (sum < best) ? PSHandWithOneCard(c1) : PSHandAddCard(filtered, c1);
                    best = sum;
                }
                trick = PSTrickRemoveLastCard(trick);
            }
            trick = PSTrickRemoveLastCard(trick);
        }
    } else if (handIndex == 2) {
        int winner = PSTrickWinner(trick, trump);
        if (winner == declarer) {
            PSCard *c1 = PSTrickCard(trick, 1);
            for (PSCardHash h = [evaluator startWithCandidates:candidates]
            ;   h != 0
            ;   h = [evaluator nextWithCandidates:candidates andCurrent:h]) {
                PSCard *c2 = [PSCard cardWithHash:h];
                PSCardRank sum = c1.rank + c2.rank;
                trick = PSTrickAddCardPlayer(trick, player, c2.compressed);
                int winner = PSTrickWinner(trick, trump);
                if (winner != declarer && sum <= best) {
                    filtered = (sum < best) ? PSHandWithOneCard(c2) : PSHandAddCard(filtered, c2);
                    best = sum;
                }
                trick = PSTrickRemoveLastCard(trick);
            }
        } else {
            filtered = lc;
        }
    }
    return filtered == 0 ? lc : filtered;
}
